<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<title>基础：10、组件 使用Slot分发内容</title>
	<script type="text/javascript" src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
	<div id="demo1">
		<son1 btn-name="son1"></son1>
		<button v-on:click="test1">{{ btnName }}</button>
	</div><br/>

	<div id="demo2">
		<h1>father</h1>
		<son2>
			<p>test1</p>
		</son2>
		<son3>
			<p>test2</p>
		</son3>
	</div><br/>

	<div id="demo3">
		<son4>
			<span slot="partOne">partOne</span>
			<span slot="partTwo">partTwo</span>
			<p>default part</p>
		</son4>
	</div><br/>
	<template id="son4">
		<div>
			<div id="partOne">
				<slot name="partOne"></slot>
			</div>
			<div id="partTwo">
				<slot name="partTwo"></slot>
			</div>
			<slot></slot>
		</div>
	</template>

	<div id="demo4">
		<son5>
			<template scope="props">
				<span>hello from parent</span><br/>
      			<span>{{ props.text }}</span>
			</template>
		</son5>
	</div>

	<script type="text/javascript">
		// 关于slot，这个什么鬼东西看起来这么玄？
		// 在前面介绍的关于组件的内容中，父组件都是body里写好的html代码，这样可以直接插入定义好的子组件
		// 那么问题来了？如果父组件有模板的话怎么把子组件插进去？<slot>元素就是用来解决这样的问题的
		// 通过slot将父组件的内容和子组件的模板组合起来，这个就叫做内容分发
		
		// ------------------------------ 编译作用域 --------------------------------
		// 编译，编译啥？
		// 
		//     当然是数据模板以及内容啦！比如在你的组件绑定的元素里使用内容模板{{ xxx }}，属性绑定v-bind:attr="xxx"，事件绑定v-on:event="xxx"等等
		//     这里的xxx可能是组件中的数据data,可能是方法methods,可能是计算属性computed,可能是过滤器filter
		//     只有经过了编译，数据、事件响应、计算等才能正常执行
		//     
		// 编译作用域？
		// 
		// 	   了解了编译后，问题又来了，父组件和子组件都要编译，它们怎么找到正确的模板呢？
		// 	   父组件的模板的内容在父组件作用域内编译；子组件的模板的内容在子组件作用域内编译
		// 	   举个栗子：
		// 	   
		// 	       <father>
		// 	           <son1 v-bind:attr1="val1">{{ msg1 }}</son1>
		// 	           <son2 @click="method2">{{ msg2 }}</son2>
		// 	           <son3 v-show="show3">{{ msg3 }}</son3>
		// 	       </father>
		// 	       
		// 	   父组件是<father>
		// 	   子组件是<son1>、<son2>、<son3>
		// 	   这里父组件开标签<father>和闭标签</father>之间的区域都是父组件的作用域，这里面有六个模板
		// 	   val1、msg1、method2、msg2、show3、msg3，它们编译时都应该去父组件实例中的选项中选择内容，
		// 	   比如method2对应father的组件定义选项中选择methods属性中的method方法		
		// 	   
		// 	   每个子组件又都有自己的内容模版
		// 	   假设子组件<son1>的定义是这样子：
		// 	   Vue.component('son1',{
		// 	   		template: '#son1',
		// 	   		data: {
		// 	   		   items: [
		// 	   		   	   { title: '红满堂论坛', link: 'http://hometown.scau.edu.cn/bbs' },
		// 	   		   	   { title: '红满堂合租宝', link: 'http://hrent.scau.edu.cn' },
		// 	   		   ]
		// 	   		},
		// 	   		...
		// 	   })
		// 	   
		// 	   <template id="#son1">
		// 	   	  <ul>
		// 	   	     <li v-for="item in items"><a href="item.link">{{ item.title }}</a></li>
		// 	   	  </ul>
		// 	   </template>
		// 	   
		// 	   在<template>这个范围内属于son1组件的作用域，items这个数据模板就对son1组件中的items
		// 	   
		// 	   PS.初学者容易将上面的msg1等模板到son1、son2中去找，主要还是没分清子组件和父组件的编译作用域
		// 	   实例demo
		Vue.component('son1',{
			props: ['btnName'],
			template: '<button v-on:click="test1">{{ btnName }}</button>',
			methods: {
				test1: function(){
					alert('son1')
				}
			}
		})
		var vm1 = new Vue({
			el: '#demo1',
			data: {
				btnName: 'vue'
			},
			methods: {
				test1: function(){
					alert('vue')
				}
			}
		})
		

		// ------------------------------ 单个Slot ---------------------------------
		// 将一个子组件插入到父组件中时，dom经过编译过后子组件自定义元素会被其dom模板所取代
		// 如果在子组件标签内还包含父组件的一些元素，这些元素会被子组件的dom模板覆盖掉
		// eg: 
		// 		<father>
		//    		<son>
		//       		<span>test</span>
		//		    </son>
		// 		</father>
		// 		
		//  son组件的dom模板是<div><h1>son</h1></div>,那么dom渲染后的效果为
		//  	<father>
		//  		<div>
		//  			<h1></h1>
		//  		</div>
		//  	</father>
		//  	
		//  如果我们想让父组件中的span不被覆盖掉，怎么办？用slot标签
		//  在son组件中为它在父组件中自定义标签内的元素预留一个位置
		//  <div>
		//  	<h1>son</h1>
		//  	<slot></slot>
		//  </div>
		//  这样渲染出来的效果如下：
		//  	<father>
		//  		<div>
		//  			<h1>son</h1>
		//  			<span>test</span>
		//  		</div>
		//  	</father>
		Vue.component('son2',{
			template: '<div><h2>son2</h2></div>'
		})
		Vue.component('son3',{
			template: '<div><h2>son3</h2><slot></slot></div>'
		})
		var vm2 = new Vue({
			el: '#demo2'
		})

		// ------------------------------ 具名Slot ---------------------------------
		// 上面的例子中只是使用了一个slot标签，如果有多个标签如何区分？
		// 可以给slot标签一个name属性，有name属性的slot标签叫具名Slot
		// 具名Slot只能被父组件中slot属性跟它的name属性相同的dom插入
		// 同时，还可以保留一个没有name属性的默认slot，用来插入没有匹配内容的父组件dom
		// eg:
		// 		<father>
		// 			<son>
		// 				<span slot="partOne">partOne</span>
		// 				<span slot="partTwo">partTwo</span>
		// 				<p>default part</p>
		// 			</son>
		// 		</father>
		// 		
		// son组件的模板为：
		// 		<div>
		// 			<div id="partOne">
		// 				<slot name="partOne"></slot>
		// 			</div>
		// 			<div id="partTwo">
		// 				<slot name="partTwo"></slot>
		// 			</div>
		// 			<slot></slot>
		// 		</div>
		// 		
		// 渲染后的效果为：
		// 		<father>
		// 			<div id="partOne">
		// 				<span>partOne</span>
		// 			</div>
		// 			<div id="partTwo">
		// 				<span>partTwo</span>
		// 			</div>
		// 			<p>default part</p>
		// 		</father>
		// 		
		// 	总结：slot其实就是给父组件中子组件内的内容预留位置插入，多个slot通过name区分
		// 	
		// 	实例demo
		Vue.component('son4',{
			template: '#son4'
		})
		var vm3 = new Vue({
			el: '#demo3'
		})

		// ------------------------------ 作用域插槽 ---------------------------------
		// 这个名词听起来也是很玄乎啊？我们拆解一下。
		// 作用域：子组件作用域和父组件作用域，前面都说得很清楚了，模板在编译的时候会认清作用域，再到对应的组件内找模板内容
		// 插槽：上面也说得很清楚了，就是子组件为父组件内容预留的一块位置
		// 
		// 那么现在问题来了，当父组件内的模板需要子组件的内容和数据怎么办？
		// 按理说父组件内的模板诸如{{ xxx }}这种玩意应该去找父组件解析啊！但是有些需求需要子组件内的数据，怎么达到这个目的？
		// 哈哈，用作用域插槽！用作用域插槽！！用作用域插槽！！！重要的事强调三遍
		// 
		// 如何使用？如下
		// 在父模板中，使用带scope属性的template作为作用域插槽，在此标签内的模板去找子组件的props属性数据解析
		// 这里scope的属性值是props，props这个变量就可以接收子组件中props的数据，变量名不一定要是props，也可以是其他的，但是建议还是用这个
		// <template scope="props"></template>
		// 
		// 实例demo:
		Vue.component('son5',{
			template: '\
						<div id="son">\
							<slot text="hello from child"></slot>\
						</div>\
					',
			props: ['text']
		})
		var vm4 = new Vue({
			el: '#demo4'
		})
	</script>
</body>
</html>
<!-- 代码均通过测试，有什么纰漏欢迎联系 QQ:1123176978  Wechat:hyhlovehuanong -->